import os
import random
import shutil
import threading
import time
import uuid
import pyautogui
import sys
import win32com
import mgrid
import win32gui
import ctypes
import tkinter as tk  
from tkinter import messagebox 

class GridInfo:
    def __init__(self,pos:tuple[int],gridSize:tuple[float],size:tuple[int]):
        self.pos = pos
        self.gridSize = gridSize
        self.size = size
    def GetPixelPos(self,x:int,y:int)->tuple[int,int]:
        px = self.pos[0] + self.gridSize[0] * (x + 0.5)
        py = self.pos[1] + self.gridSize[1] * (y + 0.5)
        return (int(px),int(py))

def DoCalc(datas:list)->list:
    input_array = (ctypes.c_int * (10 * 14))()
    for y in range(14):
        for x in range(10):
            input_array[y*10+x] = int(datas[y][x])
    array_processing_dll = ctypes.WinDLL('E:/mywork/TTT/x64/Debug/brick.dll')  
    # 设置DLL函数的参数类型和返回类型  
    # 由于我们不再返回数组，所以restype是None  
    array_processing_dll.Calc.argtypes = [ctypes.POINTER(ctypes.c_int), ctypes.c_int, ctypes.c_int, ctypes.POINTER(ctypes.c_int)]  
    array_processing_dll.Calc.restype = ctypes.POINTER(ctypes.c_int)  
    # 调用DLL函数  
    output_length = ctypes.c_int(0)  # 初始化为0，DLL函数会更新这个值
    output_array = array_processing_dll.Calc(input_array, 10, 14, ctypes.byref(output_length))  
    if output_array == None:
        return None
    moveop:list = None
    if output_length.value % 7 == 0:
        moveop = []
        for i in range(0,output_length.value,7):
            item = [output_array[i],
                    output_array[i+1],
                    output_array[i+2],
                    output_array[i+3],
                    output_array[i+4],
                    output_array[i+5],
                    output_array[i+6]]
            moveop.append(item)
    # 释放DLL分配的内存  
    array_processing_dll.FreeArray(output_array)            
    return moveop

def LoadMap(filename:str)->list:
    with open(filename,encoding='utf-8') as file:
        datas = []
        first = True
        for line in file:
            if first:
                first = False
                ss = line[:-1].split('x')
                if len(ss) < 2:
                    return None
                if ss[0] != '10':
                    return None
                if ss[1] != '14':
                    return None
            else:
                ss = line.split(' ')
                datas.append(ss)
        return datas

def CheckMap(datas:list)->bool:
    s = set()
    for data in datas:
        for item in data:
            if item in s:
                s.discard(item)
            else:
                s.add(item)
    return (len(s) == 0)
def LoadOp(filename:str)->list:
    with open(filename,encoding='utf-8') as file:
        moveops = []
        first = True
        for line in file:
            if first:
                first = False
            else:
                ss = line.split(' ')
                moveops.append(ss)
        return moveops

def RandClickMouse(x:int,y:int,randgap:int=0):
    x = x + random.randint(-randgap , randgap)
    y = y + random.randint(-randgap , randgap)
    pyautogui.click(x,y)

def RandDragMouse(x1:int,y1:int,x2:int,y2:int,sec:int,randgap:int=0):
    x1 = x1 + random.randint(-randgap , randgap)
    y1 = y1 + random.randint(-randgap , randgap)
    x2 = x2 + random.randint(-randgap , randgap)
    y2 = y2 + random.randint(-randgap , randgap)
    pyautogui.moveTo(x1, y1)
    pyautogui.dragTo(x2, y2, sec, button='left')

def recog():
    ClearVerifyFiles()
    pos = (mainwin.box.left + 14, mainwin.box.top + 152)
    grid = mgrid.MGrid("bb",pos,(42,42.5),(30,30),(10,14),0.8)
    grid.MakeData()
def parseop()->list[list[str]]:
    print('开始调入棋谱')
    datas = LoadMap("prj-bb/data/bb.txt")
    if len(datas) == 0:
        print('棋谱可能无数据')
        sys.exit(0)
    if not CheckMap(datas):
        print('请处理vreify文件')
        sys.exit(0)
    SaveVerifyFiles()
    if None == datas:
        print("load 失败")
        sys.exit(0)
    print('开始解析操作')
    moveops = DoCalc(datas)
    # moveops = LoadOp("prj-bb/op.txt")
    if moveops == None:
        print("获取移动操作失败")
    elif len(moveops)==0:
        print("获取移动操作失败2")
    return moveops

def automove(grid:GridInfo, moveops:list[list[str]]):
    for op in moveops:
        axis = str(op[0])
        distance = int(op[2])
        x = int(op[3])
        y = int(op[4])
        x2 = int(op[5])
        y2 = int(op[6])
        pxy = grid.GetPixelPos(x,y)
        pxy2 = grid.GetPixelPos(x2,y2)
        if axis == '0':
            print(f'click: ({x},{y}),({pxy[0]},{pxy[1]})')
            RandClickMouse(pxy[0],pxy[1],5)
        else:
            pxy_target = ()
            if axis == '-1':
                pxy_target = grid.GetPixelPos(x-distance,y)
            elif axis == '1':
                pxy_target = grid.GetPixelPos(x+distance,y)
            elif axis == '-2':
                pxy_target = grid.GetPixelPos(x,y-distance)
            elif axis == '2':
                pxy_target = grid.GetPixelPos(x,y+distance)
            print(f'drag: ({x},{y},{distance}),({pxy[0]},{pxy[1]})->({pxy_target[0]},{pxy_target[1]})')
            if distance > 7:
                RandDragMouse(pxy[0],pxy[1],pxy_target[0],pxy_target[1],2,5)
            else:
                RandDragMouse(pxy[0],pxy[1],pxy_target[0],pxy_target[1],1,5)
        RandClickMouse(pxy2[0],pxy2[1],5)

def giveup():
    print('开始放弃')
    exit(0)
    # RandClickMouse(mainwin.box.left + 30,mainwin.box.top + 95, 5)
    # RandClickMouse(mainwin.box.left +219,mainwin.box.top +589, 5)
    # RandClickMouse(mainwin.box.left +220,mainwin.box.top +554, 5)

def ontimer(fsmstate:int,grid:GridInfo, moveops:list[list[str]]):
    sec = 5
    try:
        if mainwin.box.left <= -32000:
            print("窗口小于-30000")
            sys.exit(0)
    except Exception as e:  
        print(f"无法访问窗口: {e}") 
        sys.exit(0)

    if fsmstate == 0:
        recog()
        fsmstate = 1
    elif fsmstate == 1:
        moveops=parseop()
        if moveops == None or len(moveops) == 0:
            fsmstate = 4
        else:
            fsmstate = 2
    elif fsmstate == 2:
        automove(grid,moveops)
        fsmstate = 3
        sec = 10
    elif fsmstate == 3:
        fsmstate = 0
    elif fsmstate == 4:
        giveup()
        fsmstate = 0
        sec = 10
    loop_monitor(sec,fsmstate,moveops)

def loop_monitor(sec,fsmstate,moveops):
    timer=threading.Timer(sec,ontimer,args=[fsmstate,grid,moveops])
    timer.start()    

def GetMainWnd():
    hwnd = win32gui.FindWindow('Chrome_WidgetWin_0', '砖了个砖')    
    if hwnd == None:
        return False
    windows = pyautogui.getWindowsWithTitle("砖了个砖")
    mainwin = None
    for w in windows:
        if w._hWnd == hwnd:
            mainwin = w
            break
    return mainwin

def ClearVerifyFiles():
    directory = 'prj-bb/verify/'
    for filename in os.listdir(directory):  
        file_path = os.path.join(directory, filename)  
        try:  
            # 如果是文件，则删除  
            if os.path.isfile(file_path):  
                os.remove(file_path)  
        except Exception as e:  
            print(f"无法删除 {file_path}. 原因: {e}") 

def IsExistVerifyFile():
    directory = 'prj-bb/verify/'
    png_exists = False  
    for filename in os.listdir(directory):  
        if filename.lower().endswith('.png'):  
            png_exists = True  
            break  # 如果只需要知道是否存在PNG文件，找到后可以退出循环 
    return png_exists

def SaveVerifyFiles():
    directory = 'prj-bb/verify/'
    directory2 = 'prj-bb/verify2/'
    if not os.path.exists(directory2):
        os.makedirs(directory2)
    for filename in os.listdir(directory):  
        file_path = os.path.join(directory, filename)
        hex_uuid = uuid.uuid4().hex
        dot_index = filename.rfind('.')
        newfilename = filename[:dot_index] + hex_uuid + filename[dot_index:]
        new_file_path = os.path.join(directory2, newfilename)
        try:  
            shutil.copy2(file_path, new_file_path)
        except Exception as e:  
            print(f"无法拷贝 {file_path}. 原因: {e}") 

if __name__ == "__main__":
    pyautogui.PAUSE = 2.5
    pyautogui.FAILSAFE = True
    print("start")
    fsmstate = 0 #0- 识别图块 1- 解析 2- 自动化走棋 3- 等待下一关 4- 放弃
    select = messagebox.askyesno("选项", "是否识别图块?\n是: 我需要识别图块\n否: 我已识别图块")
    if not select:
        fsmstate = 1
    mainwin = GetMainWnd()
    if mainwin == None:
        print("没有找到")
        sys.exit(0)
    mainwin.move(0,0)
    mainwin.activate()
    if mainwin.box.left < -32000:
        print("窗口小于-30000")
        sys.exit(0)
    moveops:list[list[str]] = []
    pos = (mainwin.box.left + 14, mainwin.box.top + 152)
    grid = GridInfo(pos,(42,42.5),(10,14))
    loop_monitor(5,fsmstate,moveops)
    print('end')

print("start2")
